using System.Collections.Generic;

namespace org.jawk.jrt
{
	/// <summary>
	/// An item which blocks until something useful can be
	/// done with the object.
	/// </summary>
	/// <remarks>
	/// An item which blocks until something useful can be
	/// done with the object.  The BlockManager multiplexes
	/// BlockObjects such that unblocking one
	/// BlockObject causes the BlockManager to dispatch
	/// the notifier tag result of the BlockObject.
	/// <p>
	/// BlockObjects are chained.  The BlockManager
	/// blocks on all chained BlockObjects until one
	/// is unblocked.
	/// <p>
	/// Subclasses must provide meaningful block()
	/// and getNotifierTag() routines.
	/// <p>
	/// BlockObjects do not actually perform the client
	/// blocking.  This is done by the BlockManager at the
	/// AVM (interpreted) or compiled runtime environment.
	/// The AVM/compiled environments make special provision
	/// to return the head block object to the BlockManager
	/// (within _EXTENSION_ keyword processing).
	/// </remarks>
	/// <seealso cref="BlockManager">BlockManager</seealso>
	/// <seealso cref="BulkBlockObject">BulkBlockObject</seealso>
	public abstract class BlockObject
	{
		protected BlockObject()
		{
		}

		/// <summary>Construct a meaningful notifier tag for this BlockObject.</summary>
		/// <remarks>Construct a meaningful notifier tag for this BlockObject.</remarks>
		public abstract string GetNotifierTag();

		/// <summary>
		/// Block until meaningful data is made available for
		/// the client application.
		/// </summary>
		/// <remarks>
		/// Block until meaningful data is made available for
		/// the client application.  This is called by the BlockManager
		/// in a way such that the BlockManager waits for one
		/// BlockObject to unblock.
		/// </remarks>
		/// <exception cref="System.Exception"></exception>
		public abstract void Block();

		private org.jawk.jrt.BlockObject next_block_object = null;

		/// <summary>Eliminate the rest of the BlockObject chain.</summary>
		/// <remarks>Eliminate the rest of the BlockObject chain.</remarks>
		public virtual void ClearNextBlockObject()
		{
			this.next_block_object = null;
		}

		/// <summary>Chain this BlockObject to another BlockObject.</summary>
		/// <remarks>
		/// Chain this BlockObject to another BlockObject.
		/// The chain is linear and there is no upper bounds on
		/// the number of BlockObjects that can be supported.
		/// </remarks>
		public virtual void SetNextBlockObject(org.jawk.jrt.BlockObject bo)
		{
			this.next_block_object = bo;
		}

		/// <summary>
		/// Obtain all chained BlockObjects as a List,
		/// including this one.
		/// </summary>
		/// <remarks>
		/// Obtain all chained BlockObjects as a List,
		/// including this one.
		/// A BlockObject chain cycle causes a runtime exception
		/// to be thrown.
		/// </remarks>
		/// <returns>
		/// A List of chained BlockObjects, including
		/// this one.
		/// </returns>
		/// <exception cref="AwkRuntimeException">
		/// if the BlockObject
		/// chain contains a cycle.
		/// </exception>
		/// <exception cref="org.jawk.jrt.AwkRuntimeException"></exception>
		public virtual System.Collections.Generic.IList<org.jawk.jrt.BlockObject> GetBlockObjects
			()
		{
			System.Collections.Generic.IList<org.jawk.jrt.BlockObject> retval = new List<BlockObject>();
			System.Collections.Generic.ICollection<org.jawk.jrt.BlockObject> bo_set = new List<BlockObject>();
			org.jawk.jrt.BlockObject @ref = this;
			while (@ref != null)
			{
				if (bo_set.Contains(@ref))
				{
					throw new org.jawk.jrt.AwkRuntimeException("Block chain contains a cycle (duplicate) : "
						 + @ref.GetType().FullName + " / " + @ref.GetNotifierTag());
				}
				else
				{
					bo_set.Add(@ref);
				}
				retval.Add(@ref);
				@ref = @ref.next_block_object;
			}
			return retval;
		}

		/// <summary>
		/// Ensure non-evaluation of a BlockObject by throwing an AWK Runtime
		/// exception, in case it leaks into AWK evaluation space.
		/// </summary>
		/// <remarks>
		/// Ensure non-evaluation of a BlockObject by throwing an AWK Runtime
		/// exception, in case it leaks into AWK evaluation space.
		/// </remarks>
		public sealed override string ToString()
		{
			throw new org.jawk.jrt.AwkRuntimeException("Extension Violation : Cannot AWK-evaluate a BlockObject."
				);
		}
	}
}
